
/**
 * AppleIIGo
 * Video Renderer class
 * (C) 2008 by Marc S. Ressl (mressl@umich.edu)
 * Released under the GPL
 * Inspired by Jim Sather's "Understanding the Apple IIe"
 */

#include "Motherboard.h"

#ifndef VIDEORENDERER_H
#define VIDEORENDERER_H

typedef enum {
	VIDEORENDERERTYPE_TV,
	VIDEORENDERERTYPE_RGB,
	VIDEORENDERERTYPE_BIT,
};

typedef enum {
	VIDEOTYPE_II,
	VIDEOTYPE_IIE,
	VIDEOTYPE_IIEENH,
	VIDEOTYPE_IIGS,
};

#define FRAMEBUFFER_X			620
#define FRAMEBUFFER_Y			460

#define VIDEOMODE_TEXT					(1 << 0)
#define VIDEOMODE_MIXED					(1 << 1)
#define VIDEOMODE_PAGE2					(1 << 2)
#define VIDEOMODE_HIRES					(1 << 3)
#define VIDEOMODE_80COL					(1 << 4)
#define VIDEOMODE_80STORE				(1 << 5)
#define VIDEOMODE_DHIRES				(1 << 6)
#define VIDEOMODE_DHIRESMONOCHROME		(1 << 7)
#define VIDEOMODE_SHIRES				(1 << 8)
#define VIDEOMODE_VIDEOTERM				(1 << 9)
#define VIDEOMODE_END					(1 << 10)

typedef enum {
	RENDERMODE_BORDER,
	RENDERMODE_TEXT,
	RENDERMODE_DTEXT,
	RENDERMODE_LORES,
	RENDERMODE_7MLORES,
	RENDERMODE_DLORES,
	RENDERMODE_HIRES,
	RENDERMODE_7HIRES,
	RENDERMODE_DHIRES,
	RENDERMODE_DHIRESMONOCHROME,
	RENDERMODE_SHIRES,
	RENDERMODE_VIDEOTERM,
	RENDERMODE_END,
};

#define TEXTPAGE1_ADDRESS			0x400
#define TEXTPAGE1_ADDRESS_END		0x800
#define TEXTPAGE2_ADDRESS			0x800
#define TEXTPAGE2_ADDRESS_END		0xC00
#define HIRESPAGE1_ADDRESS			0x2000
#define HIRESPAGE1_ADDRESS_END		0x4000
#define HIRESPAGE2_ADDRESS			0x4000
#define HIRESPAGE2_ADDRESS_END		0x6000
#define SHIRESDATA_ADDRESS			0x12000
#define SHIRESCONTROL_ADDRESS		0x19d00
#define SHIRESPALETTE_ADDRESS		0x19e00
#define SHIRESPALETTE_ENTRYNUM		256
#define SHIRESPALETTE_BYTENUM		(SHIRESPALETTE_ENTRYNUM * 2)

#define ISVIDEOMODIFIED_SCANLINE	0
#define ISVIDEOMODIFIED_TEXTLINE	230
#define ISVIDEOMODIFIED_FRAME		254
#define ISVIDEOMODIFIED_INVISIBLE	255
#define ISVIDEOMODIFIED_END			256

#define APPLEII_CHARWIDTH		7
#define APPLEII_CHARHEIGHT		8
#define APPLEII_PITCH			(HORIZ_END - HORIZ_ACTIVEVIDEO)
#define APPLEII_ROWMIXED		20
#define APPLEII_ROWNUM			24

#define VIDEOTERM_CHARWIDTH		8
#define VIDEOTERM_CHARHEIGHT	9
#define VIDEOTERM_PITCH			80
#define VIDEOTERM_ROWNUM		24

#define SHIRES_PITCH			160

#define SCANLINE_APPLEII		15
#define SCANLINE_APPLEII_MIXED	SCANLINE_APPLEII + \
								(VERT_MIXED - VERT_ACTIVEVIDEO)
#define SCANLINE_APPLEII_END	SCANLINE_APPLEII + \
								(VERT_VBL - VERT_ACTIVEVIDEO)
#define SCANLINE_SHIRES_END		SCANLINE_APPLEII + \
								(VERT_SHIRES_END - VERT_ACTIVEVIDEO)
#define SCANLINE_VIDEOTERM		7
#define SCANLINE_VIDEOTERM_NUM	(VIDEOTERM_ROWNUM * VIDEOTERM_CHARHEIGHT)
#define SCANLINE_VIDEOTERM_END	SCANLINE_VIDEOTERM + SCANLINE_VIDEOTERM_NUM
#define SCANLINE_END			230

typedef enum {
	CHARACTERSETGROUP_DEFAULT,
	CHARACTERSETGROUP_USER,
	CHARACTERSETGROUP_END,
};

#define CHARACTERSET_FLASH_FRAMENUM		0x10

#define COMPOSITE_MONOCHROME	(1 << 7)

#define NEWVIDEO_BANKLATCHDISABLED	(1 << 0)
#define NEWVIDEO_DHIRESMONOCHROME	(1 << 5)
#define NEWVIDEO_SHIRESMAP			(1 << 6)
#define NEWVIDEO_SHIRES				(1 << 7)

#define LANGUAGE_SECONDARY			(1 << 3)
#define LANGUAGE_PAL				(1 << 4)

#include "VideoMaps.h"
#include "CharacterSetLoader.h"

struct copyDataType {
	char buffer[APPLEII_ROWNUM * (APPLEII_PITCH * 2 + 1) + 1];
	UINT32 bufferIndex;
	UINT32 bufferLineIndex;
	UINT32 bufferTrimIndex;
	UINT32 bufferEndIndex;
};

class VideoRenderer : public Device {
public:
	static VideoRenderer * getInstance(UINT32 videoRendererType,
									   class Motherboard * motherboard,
									   UINT32 videoType,
									   UINT32 characterSetType,
									   char * characterSetRomImage);
	
	VideoRenderer(class Motherboard * motherboard,
				  UINT32 videoType, UINT32 characterSetType,
				  char * characterSetRomImage);
	
	void onDevicesConnected();
	void onMemoryAllocated();
	void onResetAsserted(bool isRestart);
	
	void initVideoMode();
	void setVideoMode(UINT32 value);
	
	void setText(bool value);
	bool isText();
	void setMixed(bool value);
	bool isMixed();
	void setPage2(bool value);
	bool isPage2();
	void setHires(bool value);
	bool isHires();
	
	void set80Col(bool value);
	bool is80Col();
	void set80Store(bool value);
	bool is80Store();
	void setDHires(bool value);
	bool isDHires();
	void setAltChar(bool value);
	bool isAltChar();
	
	void setMonochromeRegister(UINT8 value);
	UINT8 getMonochromeRegister();
	void setScreenColorRegister(UINT8 value);
	UINT8 getScreenColorRegister();
	void setBorderColorRegister(UINT8 value);
	UINT8 getBorderColorRegister();
	void setNewVideoRegister(UINT8 value);
	UINT8 getNewVideoRegister();
	void setLanguageRegister(UINT8 value);
	UINT8 getLanguageRegister();
	void setCharacterSetReadAddress(UINT8 value);
	UINT8 getCharacterSetReadAddress();
	bool isSHires();
	
	void setVideoterm(bool value);
	bool isVideoterm();
	
	bool loadCharacterSet(UINT32 characterSetType,
						  char * characterSetRomImage);
	void toggleCharacterSetFlash();
	void setCharacterSetLanguage(UINT32 groupIndex, UINT32 languageIndex);
	void setCharacterSetGroup(UINT32 groupIndex);
	
	UINT32 getVideoScannerAddress(UINT32 verticalCount,
								  UINT32 horizontalCount,
								  UINT32 videoMode);
	UINT8 readVideoScanner(UINT32 verticalCount, UINT32 horizontalCount);
	
	bool * getIsVideoModified();
	
	void copy(char * buffer, UINT32 bufferSize);
	bool isCopyAvailable();
	
	void setFramebuffer(UINT32 * framebuffer, UINT32 framebufferPitch);
	void setIsFramebufferUpdated(bool value);
	bool isFramebufferUpdated();
	
	void updateVideo();
	void onNextFrame();
	void onScanline(UINT32 scanlineIndex);
	virtual void renderScanline(UINT32 scanlineIndex);
	
protected:
	bool isAppleIIVideo;
	bool isAppleIIeEnhancedVideo;
	
	UINT8 * shadowMemory;
	
	UINT8 ** characterSetMap;
	UINT32 characterSetMapFlags;
	
	bool isFramebufferUpdatedValue;
	UINT32 * framebuffer;
	UINT32 framebufferPitch;
	
	UINT32 * renderMap;
	UINT32 * addressMap;
	bool isVideoModified[ISVIDEOMODIFIED_END];
	
	virtual void renderScanline(UINT32 scanlineIndex, UINT32 horizEnd);
	
private:
	class MMU * mmu;
	class TimingGenerator * timingGenerator;
	
	class VideoMaps * videoMaps;
	UINT32 ** videoModeToRenderMap;
	UINT32 ** videoModeToAddressMap;
	UINT8 ** videoModeToIsVideoModifiedMap;
	
	UINT32 videoMode;
	UINT8 monochromeRegister;
	UINT8 screenColorRegister;
	UINT8 borderColorRegister;
	UINT8 newVideoRegister;
	UINT8 languageRegister;
	UINT8 characterSetReadAddress;
	
	class CharacterSetLoader * characterSetLoader;
	UINT32 characterSetGroupIndex;
	UINT32 characterSetLanguage[CHARACTERSETGROUP_END];
	
	UINT32 frameUpdateScanlineCount;
	
	UINT32 characterSetFlashFrameIndex;
	
	void initCharacterSet(UINT32 videoType,
						  UINT32 characterSetType,
						  char * characterSetRomImage);
	void copyCharacter(struct copyDataType * copyData, UINT32 value);
	void copyLine(struct copyDataType * copyData);
};

#endif
